package com.qinglei.recoup.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qinglei.recoup.common.domain.CommonConstant;
import com.qinglei.recoup.common.domain.CommonRes;
import com.qinglei.recoup.common.domain.IotRadarStatusData;
import com.qinglei.recoup.common.domain.Tree;
import com.qinglei.recoup.common.enums.RadatStatusEnum;
import com.qinglei.recoup.common.exception.RedisConnectException;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.common.service.impl.ProductCache;
import com.qinglei.recoup.common.tenant.TenantContextHolder;
import com.qinglei.recoup.common.utils.JsonUtils;
import com.qinglei.recoup.common.utils.RecoupUtil;
import com.qinglei.recoup.common.utils.TreeUtil;
import com.qinglei.recoup.system.dao.BedInformationMapper;
import com.qinglei.recoup.system.dao.BedMapper;
import com.qinglei.recoup.system.dao.RadarMapper;
import com.qinglei.recoup.system.domain.*;
import com.qinglei.recoup.system.domain.vo.RadarBedVo;
import com.qinglei.recoup.system.enums.IotAttrEnum;
import com.qinglei.recoup.system.enums.IotLogTypeEnum;
import com.qinglei.recoup.system.pojo.*;
import com.qinglei.recoup.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author zxy
 */
@Service
@Slf4j
public class RadarServiceImpl extends ServiceImpl<RadarMapper, Radar> implements RadarService {

    @Autowired
    private RadarBedService radarBedService;
    @Autowired
    private RedisService redisService;

    @Resource
    private BedMapper bedMapper;

    @Value("${recoup.radar-offline-timeout:60}")
    private Integer radarOfflineTimeout;

    @Resource
    private BedInformationMapper bedInformationMapper;

    @Resource
    private RoomService roomService;

    @Resource
    private FloorService floorService;

    @Resource
    private BuildingService buildingService;

    @Autowired
    private ProductCache productCache;

    @Autowired
    private IotLogService iotLogService;

    /**
     * 实时数据模式、跌倒检查设置是否成功，重试次数
     */
    @Value("${hmp.device.realtime-mode.retry-count:200}")
    private Integer realtimeModeRetryCount;
    /**
     * 实时数据模式、跌倒检查设置是否成功接口，每次重试间隔时长 毫秒
     */
    @Value("${hmp.device.realtime-mode.retry-wait:300}")
    private Integer realtimeModeRetryWait;

    @Value("${hmp.device.realtime-mode.fall-down-support-key}")
    private String[] fallSupport;

    @Override
    public RadarBedPageVO showPageRadar(RadarSearchParam param) {
        RadarBedPageVO radarBedPageVO = new RadarBedPageVO();
        Page<RadarShowVO> page = new Page<>(param.getPageNum(), param.getPageSize());
        IPage<RadarShowVO> radarShowVOIPage = baseMapper.showPageRadar(page, TenantContextHolder.getTenantId(), param.getSn());
        if (radarShowVOIPage.getRecords() != null && radarShowVOIPage.getRecords().size() > 0) {
            for (RadarShowVO record : radarShowVOIPage.getRecords()) {
                if (record.getType() == null || record.getType() == 1) {
                    QueryWrapper queryWrapper = new QueryWrapper();
                    queryWrapper.eq("sn_code", record.getSnCode());
                    int n = bedInformationMapper.selectCount(queryWrapper);
                    if (n > 0) {
                        record.setExistBedMsg(true);
                    }
                    record.setSnCode(record.getSnCode() + "（床）");
                } else if (record.getType() == 2) {
                    //查看是不是支持设置跌倒设备的参数
                    record.setIsSetShow(false);

                    for (String productKey : fallSupport) {
                        if (productKey.equals(record.getIotProductKey())) {
                            record.setIsSetShow(true);
                            if (record.getIsRadarOnline() == null && fallSupport.length > 0) {
                                //设备在离线状态
                                record.setIsRadarOnline(RadatStatusEnum.OFFLINE.getNum());
                                if (this.selectRealOnlineStatus(record.getSnCode())) {
                                    record.setIsRadarOnline(RadatStatusEnum.ONLINE.getNum());
                                }
                            }
                        }

                    }
                    record.setSnCode(record.getSnCode() + "（卫生间）");
                }
            }
        }
        radarBedPageVO.setRadarShowVOIPage(radarShowVOIPage);
        radarBedPageVO.setSnCodeNum(baseMapper.selectCount(Wrappers.emptyWrapper()));
        Integer monitorBedNum = radarBedService.getMonitorBedNum(TenantContextHolder.getTenantId());
        //radarBedPageVO.setMonitorBedNum(radarBedService.count());
        radarBedPageVO.setMonitorBedNum(monitorBedNum);
        return radarBedPageVO;
    }

    /**
     * 删除监测仪
     *
     * @param id
     * @return
     */
    @Override
    public CommonRes delRadar(Integer id) {
        Integer num = radarBedService.getBaseMapper().selectCount(Wrappers.<RadarBed>lambdaQuery().eq(RadarBed::getRadarId, id));
        if (num > 0) {
            return CommonRes.failed("当前监测仪绑定床位，请解绑后再删除");
        }
        int count = baseMapper.deleteById(id);
        if (count > 0) {
            return CommonRes.ok();
        }
        return CommonRes.failed("删除失败");
    }

    @Override
    public RadarStatisticsBO selectRadarStatistics() {
        Integer tenantId = TenantContextHolder.getTenantId();
        return this.baseMapper.selectRadarStatistics(tenantId);
    }

    @Autowired
    private BedService bedService;

    @Autowired
    private VitalSignsAlarmService vitalSignsAlarmService;

//    private boolean setRadarOfflineTimeout(String sn){
//       try {
//           Bed bed = bedService.getBedBySn(sn);
//           //1.离床过久
//           String breathHightKey = "VitalSignsAlarm-"+bed.getTenantId()+"-1";
//           VitalSignsAlarm vitalSignsAlarm = vitalSignsAlarmService.getVitalSignsAlarm(breathHightKey);
//           String v4BreathTimeSsecondStr = vitalSignsAlarm.getContinued();
//           if(StringUtils.isNotBlank(v4BreathTimeSsecondStr)){
//               radarOfflineTimeout = Integer.parseInt(v4BreathTimeSsecondStr);
//           }
//           if(vitalSignsAlarm.getEnable() == 0){
//               return  true;
//           }
//       }catch (Exception e){
//           e.printStackTrace();
//       }
//
//       return  false;
//    }

    @Override
    public void updateOnlineStatus(String sn) {
//
//        if(setRadarOfflineTimeout(sn)){
//           return;
//        }
        log.debug("updateOnlineStatus sn:{}", sn);
        try {
            long l = System.currentTimeMillis() / 1000;
            long score = radarOfflineTimeout + l;
            redisService.zadd(CommonConstant.ONLINE_RADAR_ZSET_PREFIX, (double) score, sn);
        } catch (Exception e) {
            log.error("updateOnlineStatus error sn:{}", sn, e);
        }
    }

    /**
     * 更新雷达在线状态 跌倒设备
     *
     * @param sn
     */
    @Override
    public void updateOnlineStatusDownData(String sn) {
//        if(setRadarOfflineTimeoutDownData(sn)){
//            return;
//        }
        log.debug("updateOnlineStatus sn:{}", sn);
        try {
            long l = System.currentTimeMillis() / 1000;
            long score = radarOfflineTimeout + l;
            redisService.zadd(CommonConstant.ONLINE_RADAR_ZSET_PREFIX, (double) score, sn);
        } catch (Exception e) {
            log.error("updateOnlineStatus error sn:{}", sn, e);
        }
    }

//    private boolean setRadarOfflineTimeoutDownData(String sn) {
//        try {
//            Bed bed = bedService.getBedBySn(sn);
//            //1.离床过久
//            String breathHightKey = "VitalSignsAlarm-"+bed.getTenantId()+"-2";
//            VitalSignsAlarm vitalSignsAlarm = vitalSignsAlarmService.getVitalSignsAlarm(breathHightKey);
//            String v4BreathTimeSsecondStr = vitalSignsAlarm.getContinued();
//            if(StringUtils.isNotBlank(v4BreathTimeSsecondStr)){
//                radarOfflineTimeout = Integer.parseInt(v4BreathTimeSsecondStr);
//            }
//            if(vitalSignsAlarm.getEnable() == 0){
//                return true;
//            }
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//
//        return false;
//    }

    @Override
    public void updateNetworkStatus(String sn) {
        log.debug("updateNetworkStatus sn:{}", sn);
        try {
            Bed bed = bedMapper.selectBySn(sn);
            UpdateWrapper<Bed> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", bed.getId()).set("is_radar_network", 0);
            bedMapper.update(null, updateWrapper);

            //long score30 = (radarOfflineTimeout-30) + System.currentTimeMillis() / 1000;
            long score30 = 30 + System.currentTimeMillis() / 1000;
            redisService.zadd(CommonConstant.NETWORK_RADAR_ZSET_PREFIX, (double) score30, sn);
        } catch (Exception e) {
            log.error("updateNetworkStatus error sn:{}", sn, e);
        }
    }


    @Override
    public String[] getOrganizationNameBySN() {
        return this.getBaseMapper().getOrganizationNameBySN();
    }

    @Override
    public Radar selectOneNotTenant(String snCode) {
        return this.getBaseMapper().selectOneNotTenant(snCode);
    }

    @Override
    public void updateVersionAndStatusBySn(String sn, String version, Integer status) {
        Radar radar = new Radar();
        if (status != null) {
            radar.setStatus(status);
        }
        if (StringUtils.isNotEmpty(version)) {
            radar.setCurrentVersion(version);
        }
        radar.setCurrentVersion(version);
        baseMapper.update(radar, new QueryWrapper<Radar>().lambda().eq(Radar::getSnCode, sn));
    }

    @Override
    public Tree<Bed> getFallDownTree() {
        if (fallSupport.length == 0) {
            return TreeUtil.build(new ArrayList<>());
        }
        List<String> newFallDownProductKey = Arrays.asList(fallSupport);
        //获取跌倒的所有设备
        List<Radar> radarList = baseMapper.selectList(new QueryWrapper<Radar>().lambda()
                .eq(Radar::getType, Radar.TYPE_TOILET).in(Radar::getIotProductKey, newFallDownProductKey));

        if (CollectionUtils.isEmpty(radarList))
            return TreeUtil.build(new ArrayList<>());
        List<Integer> radarIds = radarList.stream().map(Radar::getId).distinct().collect(Collectors.toList());
        List<RadarBed> radarBedList = radarBedService.list(new QueryWrapper<RadarBed>().lambda().in(RadarBed::getRadarId, radarIds));
        //取2个数组的差集即为未绑定床位的sn号
        List<String> isNotBindList = radarList.stream()
                .filter(item -> !radarBedList.stream().map(e -> e.getRadarId())
                        .collect(Collectors.toList())
                        .contains(item.getId()))
                .map(Radar::getSnCode)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(radarBedList) && CollectionUtils.isEmpty(isNotBindList)) {
            return TreeUtil.build(new ArrayList<>());
        }
        Set<Integer> bedIds = radarBedList.stream().map(RadarBed::getBedId).collect(Collectors.toSet());
        Tree<Bed> bedTree = this.getBedTree(bedIds, false, true, isNotBindList);
        return bedTree;
    }

    @Override
    public CommonRes<Object> setFallDownAttr(FallDownAttrParm fallDownAttrParm) {
        //查询productkey
        Radar radar = this.selectOneNotTenant(fallDownAttrParm.getSn());
        if (Objects.isNull(radar)) {
            return CommonRes.failed("sn不存在");
        }
        String productkey = radar.getIotProductKey();
        Map<String, Object> items = this.fallDownParmBuild(fallDownAttrParm);
        Map<String, String> devicePropertyStatus = productCache.getDevicePropertyStatus(fallDownAttrParm.getSn(), productkey);
        if (devicePropertyStatus == null) {
            return CommonRes.failed("获取设备物联网属性失败");
        }
        String dproto = devicePropertyStatus.get(IotAttrEnum.DPROTO.getCode());
        Integer dprotoNum = 1;
        if (StringUtils.isNotEmpty(dproto)) {
            dprotoNum = Integer.valueOf(dproto);
        }
        items.put(IotAttrEnum.DPROTO.getCode(), dprotoNum);
        boolean res = productCache.setDevicePropertyStatus(fallDownAttrParm.getSn(), productkey, items);
        if (!res) {
            return CommonRes.failed("设置设备物联网属性失败");
        }
        int retryTimes = 0;
        //功能
        boolean funcSetStatus = false;
        //算法
        boolean algcSetStatus = false;
        while (retryTimes < this.realtimeModeRetryCount) {
            Map<String, String> propertyStatus = productCache.getDevicePropertyStatus(fallDownAttrParm.getSn(), productkey);
            if (propertyStatus == null) {
                return CommonRes.failed("获取设备物联网属性失败");
            }
            String funcCheckSet = propertyStatus.get(IotAttrEnum.FUNC.getCode());
            if (funcCheckSet != null) {
                int funcCheckGet = Integer.parseInt(funcCheckSet);
                if (items.get(IotAttrEnum.FUNC.getCode()).equals(funcCheckGet)
                        && String.valueOf(dprotoNum).equals(propertyStatus.get(IotAttrEnum.DPROTO.getCode()))) {
//                if (items.get(IotAttrEnum.FUNC.getCode()).equals(funcCheckGet)){
                    funcSetStatus = true;
                }
            }
            String algcCheckSet = propertyStatus.get(IotAttrEnum.ALGC.getCode());
            if (algcCheckSet != null) {
                int algcCheckGet = Integer.parseInt(algcCheckSet);
                if (items.get(IotAttrEnum.ALGC.getCode()).equals(algcCheckGet)
                        && String.valueOf(dprotoNum).equals(propertyStatus.get(IotAttrEnum.DPROTO.getCode()))) {
//                if (items.get(IotAttrEnum.ALGC.getCode()).equals(algcCheckGet)){
                    algcSetStatus = true;
                }
            }
            if (funcSetStatus && algcSetStatus) {
                return CommonRes.ok("设置成功");
            }
            retryTimes++;
            try {
                Thread.sleep(this.realtimeModeRetryWait);
            } catch (InterruptedException e) {
                log.error("setFallDownAttr sleep error", e);
                break;
            }
        }
        return CommonRes.failed("设置失败");
    }

    @Transactional
    @Override
    public CommonRes<Object> batchSetFallDownAttr(FallDownAttrParm fallDownAttrParm) {
        if (CollectionUtils.isEmpty(fallDownAttrParm.getSnList()))
            return CommonRes.ok();
        //查询productkey
        List<Radar> radarList = this.selectBySnList(fallDownAttrParm.getSnList());
        if (CollectionUtils.isEmpty(radarList)) {
            return CommonRes.failed("sn不存在");
        }
        Map<String, List<Radar>> iotGroupByRadarMap = radarList.stream().filter(f -> f.getIotProductKey() != null).collect(Collectors.groupingBy(Radar::getIotProductKey));
        for (Map.Entry<String, List<Radar>> stringListEntry : iotGroupByRadarMap.entrySet()) {
            List<Radar> radarIotValue = stringListEntry.getValue();
            String productkey = stringListEntry.getKey();
            Map<String, Object> items = this.fallDownParmBuild(fallDownAttrParm);
            Map<String, String> devicePropertyStatus = productCache.getDevicePropertyStatus(radarIotValue.get(0).getSnCode(), productkey);
            if (devicePropertyStatus == null) {
                return CommonRes.failed("获取设备物联网属性失败");
            }
            String dproto = devicePropertyStatus.get(IotAttrEnum.DPROTO.getCode());
            Integer dprotoNum = 1;
            if (StringUtils.isNotEmpty(dproto)) {
                dprotoNum = Integer.valueOf(dproto);
            }
            //这批量设置这里暂时先使用默认的
            items.put(IotAttrEnum.DPROTO.getCode(), dprotoNum);
            List<String> radarIotList = radarIotValue.stream().map(Radar::getSnCode).collect(Collectors.toList());
            boolean res = productCache.batchSetDeviceProperty(productkey, items, radarIotList);
            IotLog iotLog = new IotLog();
            iotLog.setIotProductKey(productkey);
            iotLog.setParm(JSON.toJSONString(items));
            iotLog.setSn(JSON.toJSONString(fallDownAttrParm.getSnList()));
            iotLog.setType(IotLogTypeEnum.BATCH_SET_FALL_DOWN.getCode());
            iotLog.setRequestId(UUID.randomUUID().toString().replace("-", ""));
            iotLog.setCreateUserId(RecoupUtil.getCurrentUser().getId());
            iotLogService.save(iotLog);
            if (!res) {
                return CommonRes.failed("设置设备物联网属性失败");
            }
            HashMap<String, String> result = new HashMap<>();
            result.put("requestId", iotLog.getRequestId());
            return CommonRes.ok(result);
        }
        return CommonRes.failed();

    }

    @Override
    public CommonRes<FallDownAttrVo> selectFallDownAttr(String sn) {
        //获取productkey
        Radar radar = this.selectOneNotTenant(sn);
        if (Objects.isNull(radar)) {
            return CommonRes.failed("sn不存在");
        }
        String productkey = radar.getIotProductKey();
        Map<String, String> propertyStatus = productCache.getDevicePropertyStatus(sn, productkey);
        if (propertyStatus == null) {
            return CommonRes.failed("获取设备物联网属性失败");
        }
        FallDownAttrVo fallDownAttrVo = new FallDownAttrVo();
        fallDownAttrVo.setSn(sn);
        if (propertyStatus.containsKey(IotAttrEnum.EXIST.getCode())) {
            fallDownAttrVo.setFallExistLamp(propertyStatus.get(IotAttrEnum.EXIST.getCode()));
        }
        if (propertyStatus.containsKey(IotAttrEnum.FALL.getCode())) {
            fallDownAttrVo.setFallLamp(propertyStatus.get(IotAttrEnum.FALL.getCode()));
        }
        if (propertyStatus.containsKey(IotAttrEnum.NET.getCode())) {
            fallDownAttrVo.setFallNetLamp(propertyStatus.get(IotAttrEnum.NET.getCode()));
        }
        if (propertyStatus.containsKey(IotAttrEnum.MONH.getCode())) {
            fallDownAttrVo.setFallMonh(propertyStatus.get(IotAttrEnum.MONH.getCode()));
        }
        if (propertyStatus.containsKey(IotAttrEnum.ALAT.getCode())) {
            fallDownAttrVo.setFallAlat(propertyStatus.get(IotAttrEnum.ALAT.getCode()));
        }
//        if(propertyStatus.containsKey(IotAttrEnum.USEH.getCode())){
//            fallDownAttrVo.setFallUseh(propertyStatus.get(IotAttrEnum.USEH.getCode()));
//        }
        return CommonRes.ok(fallDownAttrVo);
    }

    @Override
    public CommonRes<GetBatchFallAttrVo> selecBatchtFallDownAttr(String requestId) {
        List<IotLog> iotLogList = iotLogService.selectIotLogByRequestId(requestId);
        if (CollectionUtils.isEmpty(iotLogList)) {
            return CommonRes.failed("数据不存在");
        }
        HashSet<String> setSuccessSn = new HashSet<>();
        HashSet<String> setFailSn = new HashSet<>();
        Long count = 0L;
        for (IotLog iotLog : iotLogList) {
            //获取sn列表
            String snJSONList = iotLog.getSn();
            String parm = iotLog.getParm();
            List<String> snList = JSON.parseArray(snJSONList, String.class);
            Map<String, String> items = JsonUtils.jsonToMap(parm, String.class, String.class);
            for (String sn : snList) {
                Map<String, String> propertyStatus = productCache.getDevicePropertyStatus(sn, iotLog.getIotProductKey());
                if (null == propertyStatus) {
                    setFailSn.add(sn);
                    continue;
                }
                if (!propertyStatus.containsKey(IotAttrEnum.FUNC.getCode())) {
                    setFailSn.add(sn);
                    continue;
                }
                if (items.get(IotAttrEnum.FUNC.getCode()).equals(propertyStatus.get(IotAttrEnum.FUNC.getCode()))
                        && items.get(IotAttrEnum.DPROTO.getCode()).equals(propertyStatus.get(IotAttrEnum.DPROTO.getCode()))) {
//                if (items.get(IotAttrEnum.FUNC.getCode()).equals(propertyStatus.get(IotAttrEnum.FUNC.getCode()))){
                    setSuccessSn.add(sn);
                } else {
                    setFailSn.add(sn);
                }
                if (!propertyStatus.containsKey(IotAttrEnum.ALGC.getCode())) {
                    setSuccessSn.remove(sn);
                    setFailSn.add(sn);
                    continue;
                }
                if (items.get(IotAttrEnum.ALGC.getCode()).equals(propertyStatus.get(IotAttrEnum.ALGC.getCode()))
                        && items.get(IotAttrEnum.DPROTO.getCode()).equals(propertyStatus.get(IotAttrEnum.DPROTO.getCode()))) {
//                if (items.get(IotAttrEnum.ALGC.getCode()).equals(propertyStatus.get(IotAttrEnum.ALGC.getCode()))){
                    if (CollectionUtils.isEmpty(setSuccessSn) && !setFailSn.contains(sn)) {
                        setSuccessSn.add(sn);
                    }
                } else {
                    setSuccessSn.remove(sn);
                    setFailSn.add(sn);
                }
            }
            count += snList.stream().distinct().count();
        }
        GetBatchFallAttrVo getBatchFallAttrVo = new GetBatchFallAttrVo();
        Integer successSnNum = setSuccessSn.size();
        Integer failNum = setFailSn.size();
        getBatchFallAttrVo.setFailCount(failNum);
        getBatchFallAttrVo.setSuccessCount(successSnNum);
        getBatchFallAttrVo.setTotal(count);
        List<String> returnSnList = new ArrayList<>(setFailSn);
        getBatchFallAttrVo.setFailList(returnSnList);
        return CommonRes.ok(getBatchFallAttrVo);
    }

    private Map<String, Object> fallDownParmBuild(FallDownAttrParm fallDownAttrParm) {
        Map<String, Object> items = new HashMap<>();
        Random random = new Random();
        //功能下行
        if (null != fallDownAttrParm.getFallExistLamp() || null != fallDownAttrParm.getFallLamp()
                || null != fallDownAttrParm.getFallNetLamp()) {
            int funcCheckSet = random.nextInt();
            items.put(IotAttrEnum.FUNC.getCode(), funcCheckSet);
        }
        if (null != fallDownAttrParm.getFallExistLamp()) {
            items.put(IotAttrEnum.EXIST.getCode(), fallDownAttrParm.getFallExistLamp());
        }
        if (null != fallDownAttrParm.getFallLamp()) {
            items.put(IotAttrEnum.FALL.getCode(), fallDownAttrParm.getFallLamp());
        }
        if (null != fallDownAttrParm.getFallNetLamp()) {
            items.put(IotAttrEnum.NET.getCode(), fallDownAttrParm.getFallNetLamp());
        }
        //算法下行
        if (null != fallDownAttrParm.getFallMonh() || null != fallDownAttrParm.getFallAlat()) {
            int algcCheckSet = random.nextInt();
            items.put(IotAttrEnum.ALGC.getCode(), algcCheckSet);
        }
        if (null != fallDownAttrParm.getFallMonh()) {
            items.put(IotAttrEnum.MONH.getCode(), fallDownAttrParm.getFallMonh());
        }
        if (null != fallDownAttrParm.getFallAlat()) {
            items.put(IotAttrEnum.ALAT.getCode(), fallDownAttrParm.getFallAlat());
        }

        return items;
    }

    /**
     * @param bedIds
     * @param suffixBedNum 后缀是否加床位数量
     * @return
     */
    public Tree<Bed> getBedTree(Set<Integer> bedIds, boolean suffixBedNum, boolean addTotal, List<String> isNotBindList) {
        Integer bedCnt = 0;
        List<Tree<Bed>> listTree = new ArrayList<>();
        List<Bed> listBed = new ArrayList<>();
        Integer isDisabledNum = 0;
        if (CollectionUtils.isNotEmpty(bedIds)) {
            listBed = bedMapper.selectList(new QueryWrapper<Bed>().lambda().in(Bed::getId, bedIds));
            if (CollectionUtils.isEmpty(listBed)) {
                return TreeUtil.build(new ArrayList<>());
            }
            List<Integer> bedIdList = new ArrayList<>(bedIds);
            Map<Integer, RadarBedVo> radarBedMapByBedIds = radarBedService.getRadarBedMapByBedIds(bedIdList);

            Set<Integer> roomDisabled = new HashSet<>();
            Set<Integer> floorDisabled = new HashSet<>();
            Set<Integer> buildingDisabled = new HashSet<>();

            Set<Integer> setRoomIds = new HashSet<>();
            Set<Integer> setFloorIds = new HashSet<>();
            Set<Integer> setBuildingIds = new HashSet<>();
            for (Bed bed : listBed) {
                //判断是否在线
                if (bed.getIsRadarOnline() != null) {
                    if (bed.getIsRadarOnline() == 1) {
                        roomDisabled.add(bed.getRoomId());
                        floorDisabled.add(bed.getFloorId());
                        buildingDisabled.add(bed.getBuildingId());
                        isDisabledNum++;
                    }
                }
//                else {
//                    if(radarBedMapByBedIds.containsKey(bed.getId())){
//                        if(this.selectRealOnlineStatus(radarBedMapByBedIds.get(bed.getId()).getSnCode())){
//                            roomDisabled.add(bed.getRoomId());
//                            floorDisabled.add(bed.getFloorId());
//                            buildingDisabled.add(bed.getBuildingId());
//
//                        }
//                    }
//                }
                setRoomIds.add(bed.getRoomId());
                setFloorIds.add(bed.getFloorId());
                setBuildingIds.add(bed.getBuildingId());
            }
            Collection<Room> rooms = roomService.listByIds(setRoomIds);
            Collection<Floor> floors = floorService.listByIds(setFloorIds);
            Collection<Building> buildings = buildingService.listByIds(setBuildingIds);
            for (Bed bed : listBed) {
                Tree<Bed> node = new Tree<>();
                node.setId(bed.getId().toString());
                node.setKey(node.getId());
                node.setTitle(bed.getName());
                node.setType(String.valueOf(BedService.TYPE_BED));
                node.setParentId(BedService.TREE_ROOM_PREFIX + bed.getRoomId());
                node.setValue("1");
                node.setDisabled(true);
                if (radarBedMapByBedIds.containsKey(radarBedMapByBedIds.get(bed.getId()).getBedId())) {
                    node.setSnCode(radarBedMapByBedIds.get(bed.getId()).getSnCode());
                    node.setDisabled(!this.selectRealOnlineStatus(radarBedMapByBedIds.get(bed.getId()).getSnCode()));
                }
                if (bed.getIsRadarOnline() != null) {
                    node.setDisabled(bed.getIsRadarOnline() == 0);
                }
                if (node.getDisabled()) {
                    node.setTitle(bed.getName() + "（不在线）");
                }
                listTree.add(node);
            }
            for (Room room : rooms) {
                Tree<Bed> node = new Tree<>();
                node.setId(BedService.TREE_ROOM_PREFIX + room.getId().toString());
                node.setKey(node.getId());
                String title = suffixBedNum ? room.getName() + "（" + room.getBedCnt() + "床位）" : room.getName();
                node.setTitle(title);
                node.setType(String.valueOf(BedService.TYPE_ROOM));
                node.setParentId(BedService.TREE_FLOOR_PREFIX + room.getFloorId());
                node.setValue(room.getBedCnt().toString());
                if (roomDisabled.contains(room.getId())) {
                    node.setDisabled(false);
                } else {
                    node.setDisabled(true);
                }
                listTree.add(node);
            }

            for (Floor floor : floors) {
                Tree<Bed> node = new Tree<>();
                node.setId(BedService.TREE_FLOOR_PREFIX + floor.getId().toString());
                node.setKey(node.getId());
                String title = suffixBedNum ? floor.getName() + "（" + floor.getBedCnt() + "床位）" : floor.getName();
                node.setTitle(title);
                node.setType(String.valueOf(BedService.TYPE_FLOOR));
                node.setParentId(BedService.TREE_BUILDING_PREFIX + floor.getBuildingId());
                node.setValue(floor.getBedCnt().toString());
                if (floorDisabled.contains(floor.getId())) {
                    node.setDisabled(false);
                } else {
                    node.setDisabled(true);
                }
                listTree.add(node);
            }

            for (Building building : buildings) {
                Tree<Bed> node = new Tree<>();
                node.setId(BedService.TREE_BUILDING_PREFIX + building.getId().toString());
                node.setKey(node.getId());
                String title = suffixBedNum ? building.getName() + "（" + building.getBedCnt() + "床位）" : building.getName();
                node.setTitle(title);
                node.setType(String.valueOf(BedService.TYPE_BUILDING));
                if (addTotal) {
                    node.setParentId(BedService.TREE_ALL_ID);
                } else {
                    node.setParentId(null);
                }
                node.setValue(building.getBedCnt().toString());
                bedCnt += building.getBedCnt();
                if (buildingDisabled.contains(building.getId())) {
                    node.setDisabled(false);
                } else {
                    node.setDisabled(true);
                }

                listTree.add(node);
            }
        }
        if (addTotal && CollectionUtils.isNotEmpty(isNotBindList)) {
            for (String snCode : isNotBindList) {
                Tree<Bed> node = new Tree<>();
                node.setKey(node.getId());
                node.setId(BedService.IS_NOT_BIND_BED + snCode);
                node.setTitle(snCode);
                node.setType(String.valueOf(BedService.TYPE_BED));
                node.setParentId(BedService.TREE_ALL_ID);
                node.setValue(snCode);
                node.setSnCode(snCode);
                node.setDisabled(!this.selectRealOnlineStatus(snCode));
                if (node.getDisabled()) {
                    node.setTitle(snCode + "（不在线）");
                } else {
                    isDisabledNum++;
                }
                listTree.add(node);
            }

        }
        if (addTotal) {
            Tree<Bed> node = new Tree<>();
            node.setId(BedService.TREE_ALL_ID);
            node.setKey(node.getId());
            String title = suffixBedNum ? "全部卫生间" + "（" + bedCnt + "卫生间）" : "全部卫生间";
            node.setTitle(title);
            node.setType(String.valueOf(BedService.TYPE_ROOT));
            node.setParentId(null);
            node.setValue(bedCnt.toString());
            //总数量
            Integer sumDeviceNum = listBed.size() + isNotBindList.size();
            //离线数据
            Integer notOnlineNum = sumDeviceNum - isDisabledNum;
            if (sumDeviceNum.equals(notOnlineNum)) {
                node.setDisabled(true);
            } else {
                node.setDisabled(false);
            }
            listTree.add(node);
        }
        Tree<Bed> rootNode = TreeUtil.build(listTree);
        return rootNode;
    }


    @Override
    public void updateProductKey() {

        List<Radar> radarList = baseMapper.selectRadarList();
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        radarList.forEach(item -> {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    log.info("开始更新sn:{}的产品Key", item.getSnCode());
                    Map<String, Object> equipmentProductsMap = null;
                    try {
                        equipmentProductsMap = productCache.isExistEquipmentProducts(item.getSnCode());
                        boolean existEquipmentProducts = Boolean.valueOf(equipmentProductsMap.get("isExistEquipment").toString());
                        if (!existEquipmentProducts) {
                            log.info("sn:{}的产品Key不存在=======》", item.getSnCode());
                        }
                        String iotProductKey = (String) equipmentProductsMap.get("productKey");
                        item.setIotProductKey(iotProductKey);
                        baseMapper.updateById(item);
                        log.info("sn:{}的产品Key更新完成", item.getSnCode());
                    } catch (RedisConnectException e) {
                        log.error("productKey更新获取失败sn:{}", item.getSnCode());
                    }
                }
            });
        });
    }

    @Override
    public void updateProductKeyBySn(String sn, String productKey) {
        log.info("RadarServiceImpl updateProductKeyBySn,sn:{},productKey:{}",sn,productKey);
        if (StringUtils.isEmpty(sn) || StringUtils.isEmpty(productKey))
            return;
        Radar radar = baseMapper.selectOneNotTenant(sn);
        if (Objects.nonNull(radar) && !productKey.equals(radar.getIotProductKey())) {
            log.info("RadarServiceImpl updateProductKeyBySn 开始更新,sn:{},productKey:{}",sn,productKey);
            radar.setIotProductKey(productKey);
            baseMapper.update(radar, new QueryWrapper<Radar>().lambda().eq(Radar::getSnCode, sn));
        }
    }

    @Override
    public List<Radar> selectBySnList(List<String> snList) {
        return baseMapper.selectBySnList(snList);
    }

    @Override
    public void updateRealOnlineStatus(IotRadarStatusData iotRadarStatusData) {
        String sn = iotRadarStatusData.getDeviceName();
        if (StringUtils.isEmpty(sn)) {
            return;
        }
        String status = RadatStatusEnum.OFFLINE.getCode();
        if (RadatStatusEnum.ONLINE.getCode().equals(iotRadarStatusData.getStatus())) {
            status = RadatStatusEnum.ONLINE.getCode();
        }
        try {
            redisService.set(CommonConstant.ONLINE_REAL_RADAR_ZSET_PREFIX + sn, status);
        } catch (Exception e) {
            log.error("updateOnlineStatus error sn:{}", sn, e);
        }
    }

    @Override
    public Boolean selectRealOnlineStatus(String sn) {
        try {
            if (!redisService.exists(CommonConstant.ONLINE_REAL_RADAR_ZSET_PREFIX + sn)) {
                return false;
            }
            String status = redisService.get(CommonConstant.ONLINE_REAL_RADAR_ZSET_PREFIX + sn);
            if (RadatStatusEnum.OFFLINE.getCode().equals(status)) {
                return false;
            }
        } catch (RedisConnectException e) {
            return false;
        }
        return true;
    }

}
